package com.xcity.game.relation;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;

import org.slf4j.Logger;

import com.xcity.db.entity.EntityState;
import com.xcity.db.entity.Player;
import com.xcity.db.entity.Relation2;
import com.xcity.game.common.Cause;
import com.xcity.game.player.cache.PlayerCacheService;

import naga.x.App;
import naga.x.game.time.TimeUpdater;
import naga.x.util.TimeUtils;

public class Relations {

	protected RelationService service;
//	protected Player owner;
	protected long ownerId;
	protected List<Relation2>[] relations;
//	protected TLongObjectMap<Relation2>[] fastMap; // 可根据对方id快速查找对应的relation
	protected Lock lock;
	
	protected static final Logger LOG = RelationService.LOG;
	
	public Relations(Player owner, List<Relation2> friends, RelationService service) {
		this.service = service;
//		this.owner = owner;
		this.ownerId = owner.getId();
		this.relations = new List[] { friends != null ? friends : (friends = new ArrayList<Relation2>()) };
//		fastMap = new TLongObjectHashMap[] { new TLongObjectHashMap<Relation2>() };
//		TLongObjectMap<Relation2> map = fastMap[0];
//		for (int i = 0; i < friends.size(); i++) {
//			Relation2 rel = friends.get(i);
//			long destId = getDestId(rel);
//			map.put(destId, rel);
//		}
		this.lock = new ReentrantLock();
	}
	
	/**
	 * 合并内存数据
	 * @param lookup
	 */
	protected void merge(Map<Long, Relations> lookup) { // do not need lock
		List<Relation2>[] relsArr = relations;
//		TLongObjectMap<Relation2>[] relsMapArr = fastMap;
		for (byte type = 0; type < relsArr.length; type++) {
			List<Relation2> rels = relsArr[type];
//			TLongObjectMap<Relation2> relsMap = relsMapArr[type];
			for (int i = 0; i < rels.size(); i++) {
				Relation2 rel = rels.get(i);
				long destId = getDestId(rel);
				Relations cache = lookup.get(destId);
				if (cache != null) {
					Relation2 newRel = cache.find(type, ownerId);
					if (newRel != null) {
						rels.set(i, newRel);
//						relsMap.put(destId, newRel);
					} else {
						cache.add(type, rel);
					}
				}
			}
		}
	}
	
	public Relation2 find(byte type, long targetId) {
//		return fastMap[type].get(targetId);
		final Lock lock = this.lock;
		lock.lock();
		try {
			List<Relation2> list = relations[type];
			for (int i = 0; i < list.size(); i++) {
				Relation2 rel = list.get(i);
				if (targetId == getDestId(rel)) {
					return rel;
				}
			}
			return null;
		} finally {
			lock.unlock();
		}
	}
	
	public Relation2 add(byte type, Player dest) {
//		return add(type, new Relation2(owner, dest, type));
		return add(type, new Relation2(ownerId, dest.getId(), type));
	}
	
	public Relation2 add(byte type, Relation2 rel) {
		final Lock lock = this.lock;
		lock.lock();
		try {
			relations[type].add(rel);
		} finally {
			lock.unlock();
		}
//		long destId = getDestId(rel);
//		fastMap[type].put(destId, rel);
		return rel;
	}
	
	public int sizeOf(byte type) {
		return relations[type].size(); // lock?
	}
	
//	public List<Relation2> getRelations(byte type) {
//		return relations[type];
//	}
	public void forEach(byte type, Consumer<Relation2> action) {
		final Lock lock = this.lock;
		lock.lock();
		try {
			relations[type].forEach(action);
		} finally {
			lock.unlock();
		}
	}
	
	/**
	 * 获取对方玩家id
	 * @param rel
	 * @return
	 */
	public long getDestId(Relation2 rel) {
//		return rel.getSrcId() != owner.getId() ? rel.getSrcId() : rel.getDestId();
		return rel.getSrcId() != ownerId ? rel.getSrcId() : rel.getDestId();
	}
	
	public Relation2 remove(byte type, long targetId) {
//		Relation2 rel = fastMap[type].remove(targetId);
//		if (rel != null) {
//			relations[type].remove(rel);
//			rel.setState(EntityState.DELETE);
//			if (rel.getState() == EntityState.DELETE) {
//				App.getApp().getThreadPool().execute(new Runnable() {
//					@Override
//					public void run() {
//						save(rel);
//					}
//				});
//			}
//			return rel;
//		}
		
		final Lock lock = this.lock;
		lock.lock();
		try {
			List<Relation2> list = relations[type];
			for (int i = list.size() - 1; i >= 0; i--) {
				final Relation2 rel = list.get(i);
				if (targetId == getDestId(rel)) {
					rel.setState(EntityState.DELETE);
					list.remove(i);
					App.getApp().getThreadPool().execute(new Runnable() {
						@Override
						public void run() {
							save(rel);
						}
					});
					break;
				}
			}
		} finally {
			lock.unlock();
		}
		return null;
	}
	
	public void validate(Player owner) {
		final Lock lock = this.lock;
		lock.lock();
		try {
			validate0(owner);
		} finally {
			lock.unlock();
		}
	}
	
	private void validate0(Player owner) {
		List<Relation2> friends = relations[Relation2.TYPE_FRIEND];
		int size = friends.size();
		if (size == 0) {
			return;
		}
		// 计算未登录导致的亲密度掉落
		int noLoginDays = TimeUtils.diffDay(owner.getLastLogoutTime(), TimeUpdater.getInstance().now());
		int today = TimeUpdater.getInstance().today();
		PlayerCacheService pcs = App.getApp().getServiceManager().get(PlayerCacheService.class);
		for (int i = 0; i < size; i++) {
			Relation2 rel = friends.get(i);
			Player friend = pcs.find(getDestId(rel));
			if (friend != null && rel.getPool().getLastDecIntimacyDay() < today) {
				Date d = TimeUtils.getRecentDate(friend.getLastLoginTime(), friend.getLastLogoutTime());
				int days = TimeUtils.diffDay(d, TimeUpdater.getInstance().now());
				if (days < noLoginDays) {
					days = noLoginDays;
				}
				if ((days -= Relation2.CHECK_NO_LOGIN_DAYS) > 0) {
					int diffDay = today - rel.getPool().getLastDecIntimacyDay();
					if (diffDay > days) {
						diffDay = days;
					}
					int val = diffDay * Relation2.NO_LOGIN_DEC_INTIMACY;
					int oldVal = rel.getIntimacy();
					rel.decIntimacy(val > oldVal ? oldVal : val, Cause.NO_LOGIN);
					rel.getPool().setLastDecIntimacyDay(TimeUpdater.getInstance().today());
				}
			}
		}
	}
	
	public void save() { // do not need lock
		for (byte type = 0; type < relations.length; type++) {
			save(relations[type]);
		}
	}
	
	private void save(List<Relation2> rels) {
		for (int i = 0; i < rels.size(); i++) {
			Relation2 val = rels.get(i);
			save(val);
		}
	}
	
	private void save(Relation2 rel) {
		EntityState state = rel.getState();
		try {
			rel.save();
			LOG.info("[RELATION2 SAVE]ID[{}]TYPE[{}]SRC[{}]DEST[{}]OP[{}]", rel.getId(), rel.getType(), rel.getSrcId(), rel.getDestId(), state);
		} catch (Exception e) {
			LOG.error("[RELATION2 SAVE ERROR]ID[" + rel.getId()
										+ "]TYPE[" + rel.getType()
										+ "]SRC[" + rel.getSrcId()
										+ "]DEST[" + rel.getDestId()
										+ "]OP[" + state + "]", e);
		}
	}

}
